#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <pthread.h>
#include "otdrtestinterface.h"
#include "vflinterface.h"
#include "printl.h"
extern char *CurrentDateTime(char buf[]);

DeviceInfo_t    dev;
struct fpga_dev *fpgadev;

int sigint_stop = 0;

int ti = 1;
int fi = 0;
int otdrmode = 1;

#ifdef X86
int getTemperature(int *data)
{
    *data = 30000;
    return 0;
}
#endif

int stop(void)
{
    return sigint_stop;
}
void sigint_handler()
{
    sigint_stop = 1;    // SIGINT is user stop
}

int AppCallback_test(OtdrTestResult_t *upresult, OtdrTestResult_t *downresult, int en)
{
    int i, valid;
    float *Ai;
    OtdrTestResult_t *caller, *callee;

    if((upresult == NULL) || (downresult == NULL) || (en != E_CMD_OK)){
        printf("AppCallback_test : NULL pointer, or errno = %d\n", en);
    }
    else{
        caller = (OtdrTestResult_t*)upresult;
        callee = (OtdrTestResult_t*)downresult;
        valid = callee->valid;
        Ai = caller->Ai;
        if(en == E_CMD_OK){
            if(valid >= 3){
                memcpy(upresult, downresult, sizeof(OtdrTestResult_t));
            }
            if(valid >= 2){
                for(i = 0; i < caller->tp.DataNum; i++){
                    Ai[i] = callee->Ai[i];
                }
            }
            if(valid >= 1){
                memcpy(&upresult->tp, &downresult->tp, sizeof(downresult->tp));
            }
        }
        caller->Ai = Ai;
    }
    return en;
}

void printHelp(char *programname, char *subprogram)
{
    if(!strcmp(subprogram, "otdrtest")){
        printf("Usage : %s otdrtest -m 平均/实时 -l 波长(nm) -d 量程(m) -p 脉宽(ns) -t 时长(s) -n 次数\n", programname);
        printf("如 : %s otdrtest -l 1550 -d 30000 -p 160 -t 5 --> 以1550nm/30km/160ns的条件测量5秒\n", programname);
    }
    else if(!strcmp(subprogram, "autotest")){
        printf("Usage : %s autotest -l 波长(nm) -n 次数\n", programname);
        printf("如 : %s autotest -l 1550 --> 以1550nm条件自动测试一次\n", programname);
    }
    else if(!strcmp(subprogram, "cs")){
        printf("Usage : %s cs -l 波长(nm) -d 量程(m) -n 次数\n", programname);
        printf("如 : %s cs -l 1550 -d 30000 -n 5 --> 以1550nm/30km的条件测量光纤连接状态5次\n", programname);
    }
    else if(!strcmp(subprogram, "concat")){
        printf("Usage : %s concat -l 波长(nm) -d 量程(m) -p 脉宽(ns) -n 次数\n", programname);
        printf("如 : %s concat -l 1550 -d 100000 -p 1280 -n 5 --> 以1550nm/100km/1280ns的条件测量拼接参数5次\n", programname);
    }
    else if(!strcmp(subprogram, "temp")){
        printf("Usage : %s temp -i 间隔(s) -n 次数\n", programname);
        printf("如 : %s temp -n 5 --> 读取5次温度值\n", programname);
    }
    else if(!strcmp(subprogram, "vfl")){
        printf("Usage : %s vfl [off | on | blink]\n", programname);
        printf("Usage : %s vfl [0 | 1 | 2]\n", programname);
    }
    else{
        printf("otdr-algo-test tool : utilities to test otdr-algo.\n");
        printf("Usage : %s autotest | cs | concat | otdrtest\n", programname);
        printf("here, toolname is one of [autotest, cs, concat, otdrtest]\n");
    }
}

int main_autotest(int argc, char *argv[])
{
    int ch, ret, n, lambda;
    OtdrTestParam_t tp, tp2;
    
    tp.ChanNum = 0;
    tp.OtdrMode = 1;
    tp.RefreshPeriod_ms = 1000;
    tp.DataNum = 32000;

    lambda = 1550;
    n = 1;

    opterr = 0;
    while((ch = getopt(argc, argv, "l:n:")) != -1){
        switch(ch){
            case 'l':
                lambda = atoi(optarg);
                break;
            case 'n':
                n = atoi(optarg);
                break;
            default:
                break;
        }
    }

    tp.Lambda_nm = lambda;
    tp.MeasureLength_m = 0;
    tp.PulseWidth_ns = 160;
    tp.MeasureTime_ms = 15000;
    tp.n = 1.4685;
    tp.EndThreshold = 5.0;
    tp.NonReflex = 0;
    
    for(fi = 0; fi < n; fi++){
        ret = adaptTestParam(&tp, &tp2, stop, &dev);
        if(ret == E_CMD_OK){
            printf("adaptTestParam : MeasureLength_m = %dm\n",  tp2.MeasureLength_m);
            printf("adaptTestParam : PulseWidth      = %dns\n", tp2.PulseWidth_ns);
        }
        printf("return value %d\n", ret);
    }
    return ret;
}


int main_cs(int argc, char *argv[])
{
    int ch, ret, state, n, lambda, ml;
    OtdrTestParam_t tp;
    char ss[2][8] = {"good", "bad"};
    
    tp.ChanNum = 0;
    tp.OtdrMode = 1;
    tp.RefreshPeriod_ms = 1000;
    tp.DataNum = 32000;

    lambda = 1550;
    ml = 10000;
    n = 1;

    opterr = 0;
    while((ch = getopt(argc, argv, "l:d:n:")) != -1){
        switch(ch){
            case 'l':
                lambda = atoi(optarg);
                break;
            case 'd':
                ml = atoi(optarg);
                break;
            case 'n':
                n = atoi(optarg);
                break;
            default:
                break;
        }
    }

    tp.Lambda_nm = lambda;
    tp.MeasureLength_m = ml;
    tp.PulseWidth_ns = 80;
    tp.MeasureTime_ms = 15000;
    tp.n = 1.4685;
    tp.EndThreshold = 5.0;
    tp.NonReflex = 0;
    
    for(fi = 0; fi < n; fi++){
        ret = getConnectState(&tp, &state, stop, &dev);
        if(ret == E_CMD_OK){
            printf("getConnectState result: %s\n", ss[state-1]);
        }
        printf("return value %d\n", ret);
    }
    return ret;
}

int main_concat(int argc, char *argv[])
{
    int ch, ret, n, lambda, ml, pw;
    OtdrTestParam_t tp;
    ConcatParam_t cp;
    
    tp.ChanNum = 0;
    tp.OtdrMode = 1;
    tp.RefreshPeriod_ms = 1000;
    tp.DataNum = 32000;

    lambda = 1550;
    ml = 100000;
    pw = 1280;
    n = 1;

    opterr = 0;
    while((ch = getopt(argc, argv, "l:d:p:n:")) != -1){
        switch(ch){
            case 'l':
                lambda = atoi(optarg);
                break;
            case 'd':
                ml = atoi(optarg);
                break;
            case 'p':
                pw = atoi(optarg);
                break;
            case 'n':
                n = atoi(optarg);
                break;
            default:
                break;
        }
    }

    tp.Lambda_nm = lambda;
    tp.MeasureLength_m = ml;
    tp.PulseWidth_ns = pw;
    tp.MeasureTime_ms = 15000;
    tp.n = 1.4685;
    tp.EndThreshold = 5.0;
    tp.NonReflex = 0;
    
    for(fi = 0; fi < n; fi++){
        printf("=========== test %d ==============\n", fi);
        ret = getConcat(&tp, &cp, stop, &dev);
        if(ret == E_CMD_OK){
            printf("getConcat result %dnm%dkm%dns: powermode = %d, concatpoint = %d, lp = %d, lr = %d, hp = %d, hr = %d\n", \
                    tp.Lambda_nm, tp.MeasureLength_m/1000, tp.PulseWidth_ns, \
                    cp.PowerMode, cp.ConcatPoint, cp.LowPower, cp.LowRcv, cp.HighPower, cp.HighRcv);
        }
        else    printf("return value %d\n", ret);
    }
    return ret;
}

int main_getTemp(int argc, char *argv[])
{
    int i, ch, s, n, t;
    float interval, ms;

    interval = 1.0;
    n = 20;

    opterr = 0;
    while((ch = getopt(argc, argv, "i:n:")) != -1){
        switch(ch){
            case 'i':
                interval = atof(optarg);
                break;
            case 'n':
                n = atoi(optarg);
                break;
            default:
                break;
        }
    }

    s = (int)interval;
    ms = (int)(1000 * (interval - s));

    printf("%d temperature result(interval = %.3fs) :\n", n, interval);
    for(i = 0; i < n; i++){
        getTemperature(&t);
        printf("%.3f\n", t/1000.0);

        if(s > 0)   sleep(s);
        usleep(ms * 1000);
    }
    return 0;

}

int main_vfl(int argc, char *argv[])
{
    if(!strcmp(argv[1], "off")   || !strcmp(argv[1], "0")){
        printf("Turning off VFL\n");
        closeVFL(&dev);
    }
    else if(!strcmp(argv[1], "on")    || !strcmp(argv[1], "1")){
        printf("Turning on VFL\n");
        openVFL(&dev);
    }
    else if(!strcmp(argv[1], "blink") || !strcmp(argv[1], "2")){
        printf("Blinking VFL\n");
        twinkleVFL(&dev);
    }
    else{
        printf("parameter error\n");
    }
    return 0;
}

// otdr test
int main_otdrtest(int argc, char *argv[])
{
    extern int startTestAsync(void *tp, int (*AppCallback_test)(void *, void *, int), void *OtdrTestResult, int (*stop)(void), void *device);
    char  timebuf[32];
    int ch, ret, n, lambda, ml, pw, mt;

    OtdrTestParam_t tp;
    OtdrTestResult_t tr;

    tr.Ai = (float*)malloc(32000 * sizeof(float));
    
    tp.ChanNum = 0;
    tp.RefreshPeriod_ms = 1000;
    tp.DataNum = 32000;
    tp.slice_ms = 1000;

    tp.n = 1.4685;
    tp.EndThreshold = 5.0;
    tp.NonReflex = 0;

    otdrmode = 1;
    lambda = 1550;
    ml = 30000;
    pw = 160;
    mt = 5;
    n = 1;

    opterr = 0;
    while((ch = getopt(argc, argv, "m:l:d:p:t:n:")) != -1){
        switch(ch){
            case 'm':
                otdrmode = atoi(optarg);
                break;
            case 'l':
                lambda = atoi(optarg);
                break;
            case 'd':
                ml = atoi(optarg);
                break;
            case 'p':
                pw = atoi(optarg);
                break;
            case 't':
                mt = atoi(optarg);
                break;
            case 'n':
                n = atoi(optarg);
                break;
            default:
                break;
        }
    }

    tp.OtdrMode = otdrmode;
    tp.Lambda_nm = lambda;
    tp.MeasureLength_m = ml;
    tp.PulseWidth_ns = pw;
    tp.MeasureTime_ms = mt*1000;

    for(ti = 0; ti < n; ti++){
        fi = 0;
        printf("=========== test %d at time : %s ==============\n", fi, CurrentDateTime(timebuf));
        //ret = startTest(&tp, AppCallback_test, &tr, stop, &dev);
        ret = startTest(&tp, AppCallback_test, &tr, stop, &dev);
        if(ret == E_CMD_OK){
            printf("**** StartTest result: %dnm%dkm%dns%ds\n", tr.tp.Lambda_nm, tr.tp.MeasureLength_m/1000, tr.tp.PulseWidth_ns, tr.tp.MeasureTime_ms/1000);
            printf("****                   FiberLen = %.2fm, FiberLoss = %.3fdB, FiberAttenCoef = %.3fdB/km\n",
                    tr.FiberLen, tr.FiberLoss, tr.FiberAttenCoef);
            printf("finished at time : %s ==============\n", CurrentDateTime(timebuf));
        }
        printf("return value %d\n", ret);
    }

    free(tr.Ai);
    return ret;
}


int main(int argc, char *argv[])
{
    int result;

    if(argc == 1){
        printHelp(argv[0], "all");
        return 0;
    }
    else if(argc == 2){
        printHelp(argv[0], argv[1]);
    }

    signal(SIGINT, sigint_handler);

    //EN_OTDR_DBG_LEVEL(BIT_RX);
    //EN_OTDR_DBG_LEVEL(BIT_TX);

#if DATA_SPI
    result = fpga_open("/dev/spidev3.0", &fpgadev, 5000000);
    if(result == 0){}
    else{
        if(result == -1)        printf("fpga_open bus error\n");
        else if(result == -2)   printf("fpga_open unknown devID\n");
        return -1;
    }
#endif
    pthread_mutex_init(&dev.mutex_fpga, NULL);
    dev.fpga= fpgadev;
    configOtdrAlgo("/opt/TR600plus/config/otdralgo_config", 32000);

    sigint_stop = 0;
    if(strcmp(argv[1], "autotest") == 0)        main_autotest(argc-1, argv+1);
    else if(strcmp(argv[1], "cs") == 0)         main_cs      (argc-1, argv+1);
    else if(strcmp(argv[1], "concat") == 0)     main_concat  (argc-1, argv+1);
    else if(strcmp(argv[1], "otdrtest") == 0)   main_otdrtest(argc-1, argv+1);
    else if(strcmp(argv[1], "vfl") == 0)        main_vfl     (argc-1, argv+1);
    else if(strcmp(argv[1], "temp") == 0)       main_getTemp (argc-1, argv+1);
    else    printHelp(argv[0], 0);

#if DATA_SPI
    fpga_close(fpgadev);
#endif

    return 0;
}

